package com.hoshiicloud.shxping.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hoshiicloud.common.exception.CommonError;
import com.hoshiicloud.common.exception.ServiceException;
import com.hoshiicloud.common.rpc.Response;
import com.hoshiicloud.shxping.dto.CompanyDto;
import com.hoshiicloud.shxping.dto.ConsumerDto;
import com.hoshiicloud.shxping.dto.MemberAccountDto;
import com.hoshiicloud.shxping.dto.MemberDto;
import com.hoshiicloud.shxping.feign.IUserFeignService;
import com.hoshiicloud.shxping.feign.IdGeneratorService;
import com.hoshiicloud.shxping.param.MemberWithConsumerParam;
import com.hoshiicloud.shxping.service.ILoginService;
import com.hoshiicloud.shxping.util.WXCore;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * @author yangcheng
 * @version 1.0
 * @title: LoginServiceImpl
 * @description:
 * @date 2019/5/25 16:11
 * @mail maiboyc@163.com
 */
@Service
public class LoginServiceImpl implements ILoginService {

    // Id主键生成微服务FeignClient
    @Resource
    private IdGeneratorService idGeneratorService;

    // 用户微服务FeignClient
    @Resource
    private IUserFeignService userFeignService;


    /**
     * 微信登录
     * @param companyId     租户ID
     * @param platformId    平台ID
     * @param name          昵称
     * @param sex           性别
     * @param province      省份
     * @param city          城市
     * @param country       国家
     * @param headImgUrl    头像
     * @param sessionKey    微信sessionKey
     * @param openId        微信openId
     * @param appId         appId
     * @param encryptedData 密文
     * @param iv            解密参数
     * @return boolean
     */
    @Override
    public Response<Map<String,Object>> wxLogin(Long companyId, Long platformId, String invitationCode, String name, String sex, String province, String city, String country, String headImgUrl, String sessionKey, String openId, String appId, String encryptedData, String iv) throws ServiceException {
        // 返回对象
        Response<Map<String,Object>> result;
        // 解密小程序前端传过来的加密手机号码
        String telephone = decryptPhoneNumber(sessionKey,appId,encryptedData,iv);
        // 手机号码不为空
        if (StringUtils.isNotEmpty(telephone)) {
            // 根据openId和手机号码获取会员信息（只要openId和telephone任意存在都视为老用户，后台查询根据openId or telephone）
            Response<MemberDto> rs = userFeignService.getMemberByWxOpenIdOrMobile(openId,telephone);
            // 会员信息不为空
            if (null != rs && rs.getCode() == 200 && null != rs.getData()) {
                // TODO 数据库需要修改，除了用户的基本信息，第三方的登录信息需要放到平台消费者表，因为wxOpenId会不一样，qqOpenId同理。
                // 第n次登录（修改最后一次登录时间），同时查询用户是否在本平台登录过，如果登录过，只修改最后一次登录时间，如果未登录过，新增本平台的数据，同时需改最后一次登录时间
                if (StringUtils.isEmpty(rs.getData().getWxOpenId())){
                    rs.getData().setWxOpenId(openId);
                }
                // 更新会员信息
                Response<Long> update_rs = updateMember(rs.getData());
                if (null == update_rs || update_rs.getCode() != 200 || null == update_rs.getData()) {
                    throw new ServiceException(CommonError.error("更新租户会员信息失败"));
                } else {
                    Response<List<ConsumerDto>> consumer_rs = userFeignService.getConsumers(new ConsumerDto().setMemberId(update_rs.getData()));
                    if (null == consumer_rs || consumer_rs.getCode() != 200 || null == consumer_rs.getData()) {
                        Response<Long> consumer_save_rs = saveConsumer(update_rs.getData(), companyId, platformId,invitationCode);
                        if (null != consumer_save_rs && consumer_save_rs.getCode() == 200 && null != consumer_save_rs.getData()) {
                            Response account_rs = saveMemberAccount(consumer_save_rs.getData());
                            if (null == account_rs || account_rs.getCode() != 200 || null == account_rs.getData()) {
                                throw new ServiceException(CommonError.error("保存平台会员账户信息失败"));
                            } else {
                                result = getMemberWithConsumerInfo(companyId,platformId,openId);
                            }
                        } else {
                            throw new ServiceException(CommonError.error("保存平台会员信息失败"));
                        }
                    } else {
                        result = getMemberWithConsumerInfo(companyId,platformId,openId);
                    }
                }
            } else { // 第一次使用微信登录（保存相关信息到数据库）
                Response<Long> member_rs = saveMember(companyId,name, sex, province, city, country, headImgUrl, openId, telephone);
                if (null != member_rs && member_rs.getCode() == 200 && null != member_rs.getData()) {
                    Response<Long> consumer_rs = saveConsumer(member_rs.getData(), companyId, platformId,invitationCode);
                    if (null != consumer_rs && consumer_rs.getCode() == 200 && null != consumer_rs.getData()) {
                        Response account_rs = saveMemberAccount(consumer_rs.getData());
                        if (null == account_rs || account_rs.getCode() != 200 || null == account_rs.getData()) {
                            throw new ServiceException(CommonError.error("保存平台会员账户信息失败"));
                        } else {
                            result = getMemberWithConsumerInfo(companyId,platformId,openId);
                        }
                    } else {
                        throw new ServiceException(CommonError.error("保存平台会员信息失败"));
                    }
                } else {
                    throw new ServiceException(CommonError.error("保存租户会员信息失败"));
                }
            }
        } else {
            // 手机号码为空
            throw new ServiceException(CommonError.error("解密用户手机号码出错，手机号码为空"));
        }
        return result;
    }

    /**
     * 手机号+验证码登录(手机号+验证码注册)
     * @param mobile 手机号码
     * @return boolean
     */
    @Override
    public Response<Map<String,Object>> codeLogin(Long companyId, Long platformId, String mobile, String invitationCode) throws ServiceException {
        // 返回对象
        Response<Map<String,Object>> result;
        Response<MemberDto> rs = userFeignService.getMemberByMobile(companyId,mobile);
        if (null != rs && rs.getCode() == 200 && null != rs.getData()) {
            // 第n次登录（修改最后一次登录时间）
            MemberDto memberDto = rs.getData();
            memberDto.setLastLoginTime(LocalDateTime.now());
            Response<Long> update_rs = userFeignService.updateMember(memberDto);
            if (null == update_rs || update_rs.getCode() != 200 || null == update_rs.getData()) {
                throw new ServiceException(CommonError.error("更新租户会员信息失败"));
            } else {
                MemberWithConsumerParam param = new MemberWithConsumerParam();
                param.setCompanyId(companyId);// 租户ID
                param.setPlatformId(platformId);// 平台ID
                param.setPhone(mobile);// 手机号码
                result = userFeignService.getMemberWithConsumerInfo(param);
            }
        } else {
            // 第一次使用手机验证码登录（保存相关信息到数据库）
            MemberDto memberDto = new MemberDto();
            memberDto.setCompanyId(companyId);              // 租户ID
            memberDto.setPhone(mobile);                 // 手机号码
            // 调用ID生成微服务生成用户编号
            String userCode = idGeneratorService.getComUserCode();
            if (StringUtils.isEmpty(userCode)) {
                throw new ServiceException(CommonError.error("新增租户会员失败,生成会员编号失败"));
            }
            if (!StringUtils.isNotEmpty(memberDto.getNickName())) { // 如果昵称为空
                memberDto.setNickName("好获"+memberDto.getUserCode());
            }
            memberDto.setUserCode(userCode);
            memberDto.setCreatedBy("admin");
            memberDto.setCreatedTime(LocalDateTime.now());
            Response<Long> member_rs = userFeignService.saveMember(memberDto);
            if (null != member_rs && member_rs.getCode() == 200 && null != member_rs.getData()) {
                Long memberId = member_rs.getData();
                Response<Long> consumer_rs = saveConsumer(memberId, companyId, platformId,invitationCode);
                if (null != consumer_rs && consumer_rs.getCode() == 200 && null != consumer_rs.getData()) {
                    Long consumerId = consumer_rs.getData();
                    Response account_rs = saveMemberAccount(consumerId);
                    if (null == account_rs || account_rs.getCode() != 200 || null == account_rs.getData()) {
                        throw new ServiceException(CommonError.error("保存平台会员账户信息失败"));
                    } else {
                        MemberWithConsumerParam param = new MemberWithConsumerParam();
                        param.setCompanyId(companyId);// 租户ID
                        param.setPlatformId(platformId);// 平台ID
                        param.setPhone(mobile);// 手机号码
                        result = userFeignService.getMemberWithConsumerInfo(param);
                    }
                } else {
                    throw new ServiceException(CommonError.error("保存平台会员信息失败"));
                }
            } else {
                throw new ServiceException(CommonError.error("保存租户会员信息失败"));
            }
        }
        return result;
    }

    /**
     * 查询租户会员信息和平台会员信息
     * @param param 查询参数
     * @return Response<Map<String,Object>>
     */
    @Override
    public Response<Map<String, Object>> getMemberWithConsumerInfo(MemberWithConsumerParam param) {
        return userFeignService.getMemberWithConsumerInfo(param);
    }

    /**
     * 头条小程序登陆接口
     * @param companyId         租户ID
     * @param platformId        平台ID
     * @param invitationCode    邀请码
     * @param name              昵称
     * @param sex               性别
     * @param province          身份
     * @param city              城市
     * @param country           国家
     * @param headimgurl        头像地址
     * @param sessionKey        sessionKey
     * @param openId            openId
     * @param appId             appId
     * @param encryptedData     密文
     * @param iv                解密参数
     * @return boolean
     * @throws ServiceException
     */
    @Override
    public Response<Map<String, Object>> ttLogin(Long companyId, Long platformId, String invitationCode, String name, String sex, String province, String city, String country, String headimgurl, String sessionKey, String openId, String appId, String encryptedData, String iv) throws Exception {
        // 返回对象
        Response<Map<String,Object>> result = null;
        // 解密小程序前端传过来的加密手机号码
        String telephone = decryptPhoneNumber(sessionKey,appId,encryptedData,iv);
        return result;
    }

    /**
     * 保存租户会员信息
     * @param companyId     租户Id
     * @param name          昵称
     * @param sex           性别
     * @param province      省份
     * @param city          城市
     * @param country       国家
     * @param headimgurl    头像
     * @param openId        openId
     * @return Response<Long>
     */
    private Response<Long> saveMember(Long companyId,String name, String sex, String province, String city, String country, String headimgurl, String openId, String telephone) {
        // 调用主键生成微服务生成主键
        String id = idGeneratorService.queryGeneratorId();
        if (StringUtils.isEmpty(id)) {
            throw new ServiceException(CommonError.error("新增租户会员信息失败,生成ID主键失败"));
        }
        // 调用租户Service检查租户信息是否存在
        Response<CompanyDto> company = userFeignService.getCompanyById(companyId);
        if (null == company || company.getCode() != 200 || null == company.getData()) {
            throw new ServiceException(CommonError.error("新增租户会员信息失败，没有找到对应的租户信息"));
        }
        // 调用ID生成微服务生成用户编号
        String userCode = idGeneratorService.getComUserCode();
        if (StringUtils.isEmpty(userCode)) {
            throw new ServiceException(CommonError.error("新增租户会员失败,生成会员编号失败"));
        }
        MemberDto memberDto = new MemberDto();
        memberDto.setId(Long.parseLong(id));            // ID
        memberDto.setCompanyId(companyId);              // 租户ID
        memberDto.setNickName(name);                    // 昵称
        // 调用ID生成微服务生成用户编号(生成唯一编号)
        memberDto.setUserCode(getUniqueUserCode(idGeneratorService.getComUserCode()));
        if (!StringUtils.isNotEmpty(memberDto.getNickName())) { // 如果昵称为空
            memberDto.setNickName("好获"+memberDto.getUserCode());
        }
        if (StringUtils.isNotEmpty(sex)) {
            memberDto.setSex(Integer.parseInt(sex));    // 性别
        } else {
            memberDto.setSex(1);
        }
        memberDto.setWxProvince(province);              // 省份
        memberDto.setWxCity(city);                      // 城市
        memberDto.setWxCountry(country);                // 国家
        memberDto.setAvatar(headimgurl);                // 头像
        memberDto.setWxPic(headimgurl);                 // 微信头像
        memberDto.setWxOpenId(openId);                  // openId
        memberDto.setPhone(telephone);                  // 手机号码
        memberDto.setCreatedBy("admin");
        memberDto.setCreatedTime(LocalDateTime.now());
        memberDto.setModifiedBy("admin");
        memberDto.setModifiedTime(LocalDateTime.now());
        memberDto.setLastLoginTime(LocalDateTime.now());
        memberDto.setDeleted(0);
        return userFeignService.saveMember(memberDto);
    }

    /**
     * 保存平台消费者信息
     * @param memberId          注册会员ID
     * @param companyId         租户ID
     * @param platformId        平台ID
     * @param invitationCode    邀请码
     * @return Response
     */
    private Response<Long> saveConsumer(Long memberId, Long companyId, Long platformId, String invitationCode) {
        ConsumerDto consumer = new ConsumerDto();
        // 调用主键生成微服务生成主键
        String id = idGeneratorService.queryGeneratorId();
        if (id == null) {
            throw new ServiceException(CommonError.error("新增平台消费者信息失败,生成ID主键失败"));
        }
        // 调用公司微服务检查租户会员信息和租户信息是否存在
        Response member = userFeignService.getMemberById(memberId);
        if (null == member || member.getCode() != 200 || null == member.getData()) {
            throw new ServiceException(CommonError.error("新增平台消费者信息失败，没有查询到对应的租户会员信息"));
        }
        Response company = userFeignService.getCompanyById(companyId);
        if (null == company || company.getCode() != 200 || null == company.getData()) {
            throw new ServiceException(CommonError.error("新增平台消费者信息失败，没有查询到对应的租户信息"));
        }
        // 调用平台微服务检查平台信息是否存在
//        Response platform = platformFeignService.getById(entity.getPlatformid());
//        if (platform == null || platform.getCode() != 200 || platform.getData() == null ) {
//            throw new ServiceException(CommonError.error("新增用户基本信息失败，没有查询到对应的平台信息"));
//        }
        //TODO 推荐人可以为空，如果不为空调用第三方服务验证所属机构ID和推荐人ID,暂时还没弄清楚推荐人机构哪里来

        consumer.setId(Long.parseLong(id));             // ID
        consumer.setMemberId(memberId);                 // 租户会员ID
        consumer.setCompanyId(companyId);               // 租户ID
        consumer.setPlatformId(platformId);             // 平台ID
        // 上级ID
        if (StringUtils.isEmpty(invitationCode)) { // 如果不填，默认邀请码为1000962
            invitationCode = "1000962";
        }
        Response<List<ConsumerDto>> consumers = getConsumerByinviteCode(invitationCode);
        if (null != consumers && consumers.getCode() == 200 && null != consumers.getData()) {
            List<ConsumerDto> list = consumers.getData();
            if (CollectionUtils.isNotEmpty(list)) {
                consumer.setParentId(list.get(0).getId());
            } else {
                consumer.setParentId(3485546658571157520L);
            }
        } else {
            consumer.setParentId(3485546658571157520L);
        }
        // consumer.setQrCode("http://www.google.com/XXX.jpg");    // 专属二维码(图片服务器不能用，这里存个假的)
        consumer.setInviteCode(getUniqueInviteCode(idGeneratorService.getPlatCousomerCode()));// 推荐码
        consumer.setLevelId(1);                                 // 会员等级
        consumer.setLevelTime(LocalDateTime.now());             // 升级时间
        consumer.setSysToken("T93328432143214321");             // 系统token
        consumer.setPushToken("T93328432143214322");            // 推送token
        consumer.setDeviceToken("T93328432143214323");          // 设备token
        consumer.setRegShare(0);                                // 注册方式（0-普通 1-298推广注册）
        consumer.setChannel(6);                                 // 渠道（1-app 2-微信 3-pc 6-田森o2o）
        consumer.setCreatedBy("admin");
        consumer.setCreatedTime(LocalDateTime.now());
        consumer.setUpdatedBy("admin");
        consumer.setUpdatedTime(LocalDateTime.now());
        consumer.setDeleted(0);
        return userFeignService.saveConsumer(consumer);
    }

    /**
     * 保存平台消费者账户信息
     * @param consumerId 平台消费者ID
     * @return Response
     */
    private Response saveMemberAccount(Long consumerId) {
        MemberAccountDto memberAccountDto = new MemberAccountDto();
        // 调用主键生成微服务生成主键
        String id = idGeneratorService.queryGeneratorId();
        if (id == null) {
            throw new ServiceException(CommonError.error("新增平台会员账户失败,生成ID主键失败"));
        }
        // 调用用户基本信息Service检查用户账户信息是否存在
        Response<ConsumerDto> platConsumer = userFeignService.getConsumerById(consumerId);
        if (null == platConsumer || platConsumer.getCode() != 200 || null == platConsumer.getData()) {
            throw new ServiceException(CommonError.error("新增平台会员账户失败，没有找到对应的平台基本信息"));
        }
        memberAccountDto.setId(Long.parseLong(id));
        memberAccountDto.setUserId(consumerId);     // 会员ID
        memberAccountDto.setSettlement(2);          // 结算方式  1-日结 2-月结 3-45DAY 4-60DAY 5-90DAY 6-120DAY
        return userFeignService.saveMemberAccount(memberAccountDto);
    }

    private Response<List<ConsumerDto>> getConsumerByinviteCode(String inviteCode) {
        ConsumerDto param = new ConsumerDto();
        param.setInviteCode(inviteCode);
        return userFeignService.getConsumers(param);
    }

    /**
     * 解密加密串获取微信登录用户手机号码
     * @param sessionKey        sessionKey
     * @param appId             appId
     * @param encryptedData     密文
     * @param iv                解密参数
     * @return String 手机号码
     */
    private String decryptPhoneNumber(String sessionKey, String appId, String encryptedData, String iv) {
        String telephone;
        String decryptString = WXCore.decrypt(appId,encryptedData,sessionKey,iv);
        if (StringUtils.isNotEmpty(decryptString)) {
            JSONObject jsonObject = JSON.parseObject(decryptString);
            telephone = jsonObject.getString("purePhoneNumber");
        } else {
            telephone = "";
        }
        return telephone;
    }

    /**
     * 更新租户会员最后一次登录时间
     * @param entity 更新参数
     * @return Response<Long>
     */
    private Response<Long> updateMember(MemberDto entity){
        entity.setLastLoginTime(LocalDateTime.now());
        entity.setModifiedTime(LocalDateTime.now());
        entity.setModifiedBy("admin");
        return userFeignService.updateMember(entity);
    }

    /**
     * 根据租户Id、平台Id、openId获取用户信息
     * @param companyId     租户ID
     * @param platformId    平台ID
     * @param openId        openId
     * @return Response<Map<String,Object>>
     */
    private Response<Map<String,Object>> getMemberWithConsumerInfo(Long companyId,Long platformId, String openId) {
        MemberWithConsumerParam param = new MemberWithConsumerParam();
        param.setCompanyId(companyId);// 租户ID
        param.setPlatformId(platformId);// 平台ID
        param.setWxOpenId(openId);
        return userFeignService.getMemberWithConsumerInfo(param);
    }

    /**
     * 获取唯一的租户会员编号
     * @param userCode 会员编号
     * @return String
     */
    private String getUniqueUserCode(String userCode) throws ServiceException {
        String result = "";
        if (StringUtils.isNotEmpty(userCode)) {
            // 检查当前生成的userCode是否已经存在
            MemberDto m = new MemberDto();
            m.setUserCode(userCode);
            Response<List<MemberDto>> members = userFeignService.getMembers(m);
            if (null != members && members.getCode() == 200 && members.getData().size() > 0) {
                getUniqueUserCode(idGeneratorService.getComUserCode());
            } else {
                result = userCode;
            }
        } else {
            throw new ServiceException(CommonError.error("新增租户会员失败,生成会员编号失败"));
        }
        return result;
    }

    /**
     * 获取唯一的平台会员邀请码
     * @param inviteCode 邀请码
     * @return String 邀请码
     */
    private String getUniqueInviteCode(String inviteCode) {
        String result = "";
        if (StringUtils.isNotEmpty(inviteCode)) {
            // 默认生成6,7开头的邀请码
            int[] base = {6,7};
            Random random = new Random();
            int temp = random.nextInt(2);
            inviteCode = base[temp] + inviteCode.substring(1);
            // 检查当前生成的userCode是否已经存在
            ConsumerDto c = new ConsumerDto();
            c.setInviteCode(inviteCode);
            Response<List<ConsumerDto>> consumers = userFeignService.getConsumers(c);
            if (null != consumers && consumers.getCode() == 200 && consumers.getData().size() > 0) {
                getUniqueInviteCode(idGeneratorService.getPlatCousomerCode());
            } else {
                result = inviteCode;
            }
        }
        return result;
    }

}
